package com.hitqz.robot.biz.controller;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.spring.SpringUtil;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.google.common.cache.Cache;
import com.hitqz.robot.api.business.dto.RobotClientSummaryDto;
import com.hitqz.robot.api.business.entity.RobotEntity;
import com.hitqz.robot.api.business.entity.RobotGroupEntity;
import com.hitqz.robot.api.business.entity.RobotJobEntity;
import com.hitqz.robot.api.business.params.PageRobotJobParams;
import com.hitqz.robot.api.business.params.RobotJobParams;
import com.hitqz.robot.api.business.vo.RobotJobCalendarDayVo;
import com.hitqz.robot.api.business.vo.RobotJobCalendarMonthNewVo;
import com.hitqz.robot.api.business.vo.RobotJobCalendarMonthVo;
import com.hitqz.robot.api.business.vo.RobotJobVo;
import com.hitqz.robot.api.dispatch.protocol.dto.FormConfigModalDto;
import com.hitqz.robot.api.dispatch.protocol.dto.FormFieldConfigModalDto;
import com.hitqz.robot.biz.service.RobotGroupService;
import com.hitqz.robot.biz.service.RobotJobService;
import com.hitqz.robot.biz.service.RobotService;
import com.hitqz.robot.common.core.util.R;
import com.hitqz.robot.common.core.util.RedisUtils;
import com.hitqz.robot.common.log.annotation.SysLog;
import com.hitqz.robot.daemon.quartz.entity.SysJob;
import com.hitqz.robot.daemon.quartz.service.SysJobService;
import com.hitqz.robot.daemon.quartz.util.TaskUtil;
import com.pig4cloud.plugin.excel.annotation.ResponseExcel;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.security.SecurityRequirement;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.springdoc.core.annotations.ParameterObject;
import org.springframework.http.HttpHeaders;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;

import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 机器人任务管理表
 *
 * @author wengyongxin
 * @date 2024-05-31 15:41:27
 */
@RestController
@RequiredArgsConstructor
@RequestMapping("/robotJob")
@Tag(description = "robotJob", name = "机器人任务管理表管理")
@SecurityRequirement(name = HttpHeaders.AUTHORIZATION)
@Slf4j
public class RobotJobController {

    private final RobotJobService robotJobService;

    private final SysJobService sysJobService;

    private final RobotGroupService robotGroupService;

    private final RobotService robotService;

    private final TaskUtil taskUtil;

    private final Scheduler scheduler;

    /**
     * 分页查询
     *
     * @param page     分页对象
     * @param robotJob 机器人任务管理表
     * @return
     */
    /**
     * 分页查询
     *
     * @param page     分页对象
     * @param robotJob 机器人任务管理表
     * @return
     */
    @Operation(summary = "分页查询", description = "分页查询")
    @GetMapping("/page")
    @PreAuthorize("@pms.hasPermission('web_robotJob_view')")
    public R<Page<RobotJobVo>> getRobotJobPage(@ParameterObject Page page,
                                               @ParameterObject PageRobotJobParams robotJob) {
        if (page.getCurrent() <= 0 || page.getSize() <= 0) {
            throw new IllegalArgumentException("Invalid page parameters");
        }

        if (robotJob == null) {
            throw new IllegalArgumentException("Invalid robotJob parameters");
        }

        LambdaQueryWrapper<RobotJobEntity> wrapper = Wrappers.lambdaQuery();
        wrapper.like(StrUtil.isNotBlank(robotJob.getName()), RobotJobEntity::getName, robotJob.getName());
        wrapper.eq(StrUtil.isNotBlank(robotJob.getEnable()), RobotJobEntity::getEnable, robotJob.getEnable());
        if (StrUtil.isNotBlank(robotJob.getRobotSn())) {
            RobotEntity robot = robotService.selectByRobotSn(robotJob.getRobotSn());
            wrapper.eq(Objects.nonNull(robot), RobotJobEntity::getGroupId, robot.getGroupId());
        }

        Page<RobotJobEntity> robotJobEntityPage = robotJobService.page(page, wrapper);
        Page<RobotJobVo> robotJobVoPage = convertToRobotJobVoPage(robotJobEntityPage);
        return R.ok(robotJobVoPage);
    }

    private Page<RobotJobVo> convertToRobotJobVoPage(Page<RobotJobEntity> robotJobEntityPage) {
        Page<RobotJobVo> robotJobVoPage = new Page<>();
        robotJobVoPage.setTotal(robotJobEntityPage.getTotal());
        robotJobVoPage.setCurrent(robotJobEntityPage.getCurrent());
        robotJobVoPage.setPages(robotJobEntityPage.getPages());
        robotJobVoPage.setSize(robotJobEntityPage.getSize());
        Set<Integer> groupIds = robotJobEntityPage.getRecords().stream()
                .map(RobotJobEntity::getGroupId)
                .collect(Collectors.toSet());
        if (groupIds.size() >0) {
            Map<Integer, RobotGroupEntity> groupMap = robotGroupService.listByIds(groupIds).stream()
                    .collect(Collectors.toMap(RobotGroupEntity::getId, Function.identity()));
            List<RobotJobVo> robotJobVos = robotJobEntityPage.getRecords().stream()
                    .map(this::convertToRobotJobVo)
                    .peek(robotJobVo -> robotJobVo.setGroupName(groupMap.getOrDefault(robotJobVo.getGroupId(), new RobotGroupEntity()).getName()))
                    .collect(Collectors.toList());

            robotJobVoPage.setRecords(robotJobVos);
        }

        return robotJobVoPage;
    }

    private RobotJobVo convertToRobotJobVo(RobotJobEntity robotJobEntity) {
        RobotJobVo robotJobVo = new RobotJobVo();
        BeanUtil.copyProperties(robotJobEntity, robotJobVo);
        robotJobVo.setEnable(String.valueOf(robotJobEntity.getEnable()));

        try {
            FormConfigModalDto formConfigModalDto = JSONObject.parseObject(robotJobEntity.getContent(), FormConfigModalDto.class);
            StringBuffer stringBuffer = new StringBuffer();
            for (FormFieldConfigModalDto modalDto : formConfigModalDto.getFields()) {
                String currentValue = modalDto.getCurrentValue();
                List<String> optionsList = modalDto.getOptions();
                if (optionsList != null) {
                    List<Map> parsedOptions = optionsList.stream()
                            .map(option -> JSONObject.parseObject(option, Map.class))
                            .toList();
                    for (Map<String, Object> options : parsedOptions) {
                        Optional<String> valueOpt = Optional.ofNullable(options.get("value")).map(Object::toString);
                        Optional<String> labelOpt = Optional.ofNullable(options.get("label")).map(Object::toString);
                        if (valueOpt.isPresent() && Objects.equals(valueOpt.get(), currentValue) && labelOpt.isPresent()) {
                            currentValue = labelOpt.get();
                            break;
                        }
                    }
                }
                stringBuffer.append(modalDto.getLabel() + ":" + currentValue + ";");
            }
            robotJobVo.setContent(stringBuffer.toString());
        } catch (Exception e) {
            log.error("Failed to parse JSON content: {}", robotJobEntity.getContent(), e);
            throw new RuntimeException("Failed to parse JSON content", e);
        }

        return robotJobVo;
    }


    /**
     * 通过id查询机器人任务管理表
     *
     * @param id id
     * @return R
     */
    @Operation(summary = "通过id查询", description = "通过id查询")
    @GetMapping("/{id}")
    @PreAuthorize("@pms.hasPermission('web_robotJob_view')")
    public R<RobotJobVo> getById(@PathVariable("id") Integer id) {
        RobotJobVo robotJobVo = new RobotJobVo();
        RobotJobEntity robotJobEntity = robotJobService.getById(id);
        BeanUtil.copyProperties(robotJobEntity, robotJobVo);
        RobotGroupEntity robotGroup = robotGroupService.getById(robotJobEntity.getGroupId());
        robotJobVo.setGroupName(robotGroup == null ? "" : robotGroup.getName());
        if (StrUtil.isNotBlank(robotJobEntity.getContent())) {
            robotJobVo.setModalData(JSONObject.parseObject(robotJobEntity.getContent(), FormConfigModalDto.class));
        }
        return R.ok(robotJobVo);
    }

    /**
     * 新增机器人任务管理表
     *
     * @param addRobotJobVo 机器人任务管理表
     * @return R
     */
    @Operation(summary = "新增机器人任务管理表", description = "新增机器人任务管理表")
    @SysLog("新增机器人任务管理表")
    @PostMapping
    @PreAuthorize("@pms.hasPermission('web_robotJob_add')")
    public R save(@RequestBody RobotJobParams addRobotJobVo) throws SchedulerException {
        RobotJobEntity robotJobEntity = new RobotJobEntity();
        BeanUtil.copyProperties(addRobotJobVo, robotJobEntity);
        if (StrUtil.isNotBlank(addRobotJobVo.getCron())) {
            // 添加任务
            SysJob exitJob = sysJobService.getOne(Wrappers.<SysJob>lambdaQuery().eq(SysJob::getJobName, addRobotJobVo.getName()).last("limit 1"));
            if (exitJob != null) {
                return R.failed("已存在该任务");
            }
            if (StrUtil.isEmpty(robotJobEntity.getContent())) {
                robotJobEntity.setContent(JSONObject.toJSONString(addRobotJobVo.getModalData()));
            }
            robotJobService.save(robotJobEntity);
            //
            SysJob sysJob = sysJobService.addJobByRobotJob(addRobotJobVo.getName(), addRobotJobVo.getCron(), String.valueOf(robotJobEntity.getId()));
            if (Objects.equals(addRobotJobVo.getEnable(), "1")) {
                sysJobService.startJob(sysJob.getJobId());
            } else {
                sysJobService.pauseJob(sysJob.getJobId());
            }
        } else {
            return R.failed("表达式不能为空");
        }
        return R.ok();
    }

    /**
     * 修改机器人任务管理表
     *
     * @param robotJobParams 机器人任务管理表
     * @return R
     */
    @Operation(summary = "修改机器人任务管理表", description = "修改机器人任务管理表")
    @SysLog("修改机器人任务管理表")
    @PutMapping
    @PreAuthorize("@pms.hasPermission('web_robotJob_edit')")
    public R updateById(@RequestBody RobotJobParams robotJobParams) throws SchedulerException {
        RobotJobEntity robotJobEntity = robotJobService.getById(robotJobParams.getId());
        if (robotJobEntity == null) {
            return R.failed("该数据已经删除");
        }
        if (!JSONUtil.isTypeJSON(robotJobParams.getContent())) {
            robotJobParams.setContent(robotJobEntity.getContent());
        }
        BeanUtil.copyProperties(robotJobParams, robotJobEntity, false);
        if (StrUtil.isEmpty(robotJobEntity.getContent())) {
            robotJobEntity.setContent(JSONObject.toJSONString(robotJobParams.getModalData()));
        }
        SysJob sysJob = sysJobService.getOne(Wrappers.<SysJob>lambdaQuery().eq(SysJob::getMethodParamsValue, String.valueOf(robotJobParams.getId())).last("limit 1"));
        if (sysJob == null) {
            sysJob = sysJobService.addJobByRobotJob(robotJobParams.getName(), robotJobParams.getCron(), String.valueOf(robotJobEntity.getId()));
        }
        //暂停
        sysJobService.pauseJob(sysJob.getJobId());
        //更新时间表达式
        sysJobService.updateById(SysJob.builder()
                .jobId(sysJob.getJobId())
                .cronExpression(robotJobParams.getCron())
                .build());
        // 如修改暂停的需更新调度器
        taskUtil.addOrUpateJob(sysJobService.getById(sysJob.getJobId()), scheduler);
        if (Objects.equals(robotJobParams.getEnable(), "1")) {
            sysJobService.startJob(sysJob.getJobId());
        }
        robotJobService.updateById(robotJobEntity);
        return R.ok();
    }

    /**
     * 通过id删除机器人任务管理表
     *
     * @param ids id列表
     * @return R
     */
    @Operation(summary = "通过id删除机器人任务管理表", description = "通过id删除机器人任务管理表")
    @SysLog("通过id删除机器人任务管理表")
    @DeleteMapping
    @PreAuthorize("@pms.hasPermission('web_robotJob_del')")
    public R removeById(@RequestBody Integer[] ids) throws SchedulerException {
        for (Integer id : ids) {
            RobotJobEntity robotJobEntity = robotJobService.getById(id);
            SysJob sysJob = sysJobService.getOne(Wrappers.<SysJob>lambdaQuery().eq(SysJob::getMethodParamsValue,
                    String.valueOf(robotJobEntity.getId())).last("limit 1"));
            if (sysJob !=null) {
                sysJobService.pauseJob(sysJob.getJobId());
                taskUtil.removeJob(sysJob, scheduler);
                sysJobService.removeById(sysJob);
            }
        }
        return R.ok(robotJobService.removeBatchByIds(CollUtil.toList(ids)));
    }


    /**
     * 导出excel 表格
     *
     * @param robotJob 查询条件
     * @param ids      导出指定ID
     * @return excel 文件流
     */
    @ResponseExcel
    @GetMapping("/export")
    @PreAuthorize("@pms.hasPermission('web_robotJob_export')")
    public List<RobotJobEntity> export(RobotJobEntity robotJob, Integer[] ids) {
        return robotJobService.list(Wrappers.lambdaQuery(robotJob).in(ArrayUtil.isNotEmpty(ids), RobotJobEntity::getId, ids));
    }


    /**
     * 通过id执行机器人任务管理表
     *
     * @param id id
     * @return R
     */
    @Operation(summary = "通过id执行任务", description = "通过id执行任务")
    @GetMapping("/execute/{id}")
    @PreAuthorize("@pms.hasPermission('web_robotJob_execute')")
    public R execute(@PathVariable("id") Integer id) throws SchedulerException {
        RobotJobEntity robotJobEntity = robotJobService.getById(id);
        if (robotJobEntity == null) {
            return R.failed("任务已经被删除");
        }
        SysJob sysJob = sysJobService.getOne(Wrappers.<SysJob>lambdaQuery().eq(SysJob::getMethodParamsValue, String.valueOf(robotJobEntity.getId())).last("limit 1"));
        if (sysJob == null) {
            return R.failed("任务异常，无法执行");
        }
        return sysJobService.runOneJob(sysJob.getJobId()) ? R.ok() : R.failed("执行失败");
    }


    @Operation(summary = "获取任务日历-月")
    @GetMapping("/calendar/{year}/{month}")
    public R<List<RobotJobCalendarMonthVo>> calendar(@PathVariable(value = "year")@Parameter(description = "年 yyyy") String year,
                                                     @PathVariable(value = "month")@Parameter(description = "月 MM") String month) {
        DateTime date = DateUtil.parse(year + "-" + month + "-01", "yyyy-MM-dd");
        return R.ok(robotJobService.calendarMonth(date));
    }



    @Operation(summary = "获取任务日历-日")
    @GetMapping("/calendar/{year}/{month}/{day}")
    public R<List<RobotJobCalendarDayVo>> calendar(@PathVariable(value = "year")@Parameter(description = "年 yyyy") String year,
                                                   @PathVariable(value = "month")@Parameter(description = "月 MM") String month,
                                                   @PathVariable(value = "day")@Parameter(description = "日 dd") String day) {
        DateTime date = DateUtil.parse(year + "-" + month + "-"+day, "yyyy-MM-dd");
        return R.ok(robotJobService.calendarDay(date));
    }



    @Operation(summary = "获取任务日历-月-新")
    @GetMapping("/newCalendar/{year}/{month}")
    public R<List<RobotJobCalendarMonthNewVo>> newCalendar(@PathVariable(value = "year")@Parameter(description = "年 yyyy") String year,
                                                           @PathVariable(value = "month")@Parameter(description = "月 MM") String month) {
        Date startDate = DateUtil.beginOfMonth(DateUtil.parse(year + "-" + month + "-01", "yyyy-MM-dd 00:00:00"));
        Date endData = DateUtil.endOfMonth(DateUtil.parse(year + "-" + month + "-01", "yyyy-MM-dd 00:00:00"));
        //DateTime date = DateUtil.parse(year + "-" + month + "-01", "yyyy-MM-dd 00:");
        //DateTime endData = DateUtil.parse(year + "-" + month + "-01", "yyyy-MM-dd");
        // robotJobService.calendarMonthNew(date)
        return R.ok();
    }


    @Operation(summary = "获取任务日历-日-新")
    @GetMapping("/newCalendar/{year}/{month}/{day}")
    public R<List<RobotJobCalendarDayVo>> newCalendar(@PathVariable(value = "year")@Parameter(description = "年 yyyy") String year,
                                                   @PathVariable(value = "month")@Parameter(description = "月 MM") String month,
                                                   @PathVariable(value = "day")@Parameter(description = "日 dd") String day) {
        DateTime date = DateUtil.parse(year + "-" + month + "-"+day, "yyyy-MM-dd");
        return R.ok(robotJobService.calendarDayNew(date));
    }


    @Operation(summary = "获取调度组机器人任务数据")
    @GetMapping(value = "dynamicTaskContent")
    public R<FormConfigModalDto> dynamicTaskContent(@RequestParam(value = "groupId") Integer groupId) {
        List<RobotEntity> robotEntityList = robotService.list(Wrappers.<RobotEntity>lambdaQuery()
                .eq(RobotEntity::getGroupId, groupId));
        Cache<String, RobotClientSummaryDto> posInfoDtoCache = SpringUtil.getBean("robotCache");
        String robotSn = "";
        for (RobotEntity robotEntity : robotEntityList) {
            if (posInfoDtoCache.getIfPresent(robotEntity.getRobotSn()) != null) {
                robotSn = robotEntity.getRobotSn();
                break;
            }
        }
        if (StrUtil.isEmpty(robotSn)) {
            return R.failed("该调度组没有机器人在线无法编辑");
        }
        String jsonString = RedisUtils.get("dynamicTaskContent:" + robotSn);
        FormConfigModalDto formConfigModalDto = null;
        if (StrUtil.isNotBlank(jsonString)){
            formConfigModalDto = JSONObject.parseObject(jsonString, FormConfigModalDto.class);
        }
        return R.ok(formConfigModalDto);
    }








}